package com.dongrj.framework.core.utils;

import com.dongrj.framework.core.exception.Assert;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
import lombok.extern.slf4j.Slf4j;

import java.io.Serializable;
import java.lang.reflect.Array;
import java.math.BigDecimal;
import java.util.*;
import java.util.function.*;
import java.util.stream.Collectors;

/**
 * @author dongrongjun
 * @date 2020/08/04
 * 集合工具类
 */

@Slf4j
public final class CollectionUtils {

    private static final Integer ZERO = 0;

    /**
     * 获取集合的Size
     *
     * @param collection 集合
     */
    public static <T> List<T> nullToEmpty(List<T> collection) {
        if (collection == null) {
            return Lists.newArrayListWithCapacity(0);
        }
        return collection;
    }

    /**
     * 获取集合的Size
     *
     * @param collection 集合
     */
    public static <T, R> List<R> map(List<T> collection, Function<T, R> trFunction) {
        if (collection == null) {
            log.info("集合为空返回空集合!");
            return Lists.newArrayListWithCapacity(0);
        }
        List<R> result = Lists.newArrayListWithExpectedSize(CollectionUtils.size(collection));
        for (T t : collection) {
            if (Objects.nonNull(t)) {
                R apply = trFunction.apply(t);
                result.add(apply);
            } else {
                log.info("集合元素为空跳过!");
            }
        }
        return result;
    }

    /**
     * 字符串拼接
     *
     * @param collection 集合
     */
    public static <T> String join(List<T> collection, Function<T, String> trFunction) {
        return join(collection, trFunction, ",");
    }

    /**
     * 字符串拼接
     *
     * @param collection 集合
     */
    public static <T> String join(List<T> collection, Function<T, String> trFunction, String delimiter) {
        if (collection == null) {
            return null;
        }
        return collection.stream().filter(Objects::nonNull).map(trFunction).collect(Collectors.joining(delimiter));
    }

    /**
     * 获取集合的Size
     *
     * @param collection 集合
     */
    public static <T> int size(Collection<T> collection) {
        return size(collection, false);
    }

    /**
     * 获取集合的Size
     *
     * @param collection 集合
     */
    public static <T> int size(T[] collection) {
        return size(collection, false);
    }


    /**
     * 获取集合的Size
     *
     * @param collection 集合
     * @param filter     是否忽略空对象
     */
    public static <T> int size(Collection<T> collection, boolean filter) {
        if (Objects.isNull(collection)) {
            return ZERO;
        }
        if (filter) {
            long count = collection.stream().filter(Objects::nonNull).count();
            return new Long(count).intValue();
        }
        return collection.size();
    }

    /**
     * 获取集合的Size
     *
     * @param collection 集合
     * @param filter     是否忽略空对象
     */
    public static <T> int size(T[] collection, boolean filter) {
        if (Objects.isNull(collection)) {
            return ZERO;
        }
        if (filter) {
            long count = Arrays.stream(collection).filter(Objects::nonNull).count();
            return new Long(count).intValue();
        }
        return collection.length;
    }

    /**
     * 判断集合的Size
     *
     * @param collection 集合
     */
    public static <T> boolean sizeEquals(Collection<T> collection, int size) {
        return sizeEquals(collection, size, false);
    }

    /**
     * 判断集合的Size
     */
    public static <A1, A2> boolean sizeEquals(A1[] a1s, A2[] a2s) {
        return sizeEquals(a1s, a2s, false);
    }

    /**
     * 判断集合的Size
     */
    public static <A1, A2> boolean sizeEquals(A1[] a1s, A2[] a2s, boolean filter) {
        return size(a1s, filter) == size(a2s, filter);
    }

    /**
     * 判断集合的Size
     *
     * @param collection 集合
     * @param size       集合大小
     * @param filter     是否忽略空对象
     */
    public static <T> boolean sizeEquals(Collection<T> collection, int size, boolean filter) {
        return size(collection, filter) == size;
    }

    /**
     * 判断集合的Size相等
     *
     * @param collection1 集合1
     * @param collection1 集合2
     */
    public static <T1, T2> boolean sizeEquals(Collection<T1> collection1, Collection<T2> collection2) {
        return sizeEquals(collection1, collection2, false);
    }


    /**
     * Map是否为空
     *
     * @param map map
     */
    public static boolean isEmpty(Map<?, ?> map) {
        return (map == null || map.isEmpty());
    }

    /**
     * Map不为空
     *
     * @param map map
     */
    public static boolean isNotEmpty(Map<?, ?> map) {
        return !isEmpty(map);
    }


    /**
     * 判断集合的Size相等
     *
     * @param collection1 集合1
     * @param collection1 集合2
     * @param filter      是否忽略空对象
     */
    public static <T1, T2> boolean sizeEquals(Collection<T1> collection1, Collection<T2> collection2, boolean filter) {
        return size(collection1, filter) == size(collection2, filter);
    }


    /**
     * 判断集合的Size不相等
     *
     * @param collection1 集合1
     * @param collection1 集合2
     */
    public static <T1, T2> boolean sizeNotEquals(Collection<T1> collection1, Collection<T2> collection2) {
        return sizeNotEquals(collection1, collection2, false);
    }


    /**
     * 判断集合的Size不相等
     *
     * @param collection1 集合1
     * @param collection1 集合2
     * @param filter      是否忽略空对象
     */
    public static <T1, T2> boolean sizeNotEquals(Collection<T1> collection1, Collection<T2> collection2, boolean filter) {
        return !sizeEquals(collection1, collection2, filter);
    }


    /**
     * 判断集合是不是空||size=0
     *
     * @param collection 集合
     */
    public static <T> boolean isEmpty(Collection<T> collection) {
        return isEmpty(collection, false);
    }

    /**
     * 判断集合是不是空||size=0
     *
     * @param collection 集合
     * @param filter     是否忽略空对象
     */
    public static <T> boolean isEmpty(Collection<T> collection, boolean filter) {
        return sizeEquals(collection, ZERO, filter);
    }


    /**
     * 空还回
     *
     * @param collection 集合
     */
    public static <T, R> R isEmptyDefault(List<T> collection, Function<List<T>, R> function, R r) {
        if (isEmpty(collection)) {
            return r;
        }
        return function.apply(collection);
    }


    /**
     * 判断集合是否Size>0
     *
     * @param collection 集合
     */
    public static <T> boolean isNotEmpty(Collection<T> collection) {
        return isNotEmpty(collection, false);
    }

    /**
     * 判断集合是否Size>0
     *
     * @param collection 集合
     * @param filter     是否忽略空对象
     */
    public static <T> boolean isNotEmpty(Collection<T> collection, boolean filter) {
        return !isEmpty(collection, filter);
    }

    /**
     * 获取集合中第一个元素
     *
     * @param collection 集合
     */
    public static <T> Optional<T> first(Collection<T> collection) {
        if (isNotEmpty(collection)) {
            return collection.stream().findFirst();
        }
        return Optional.empty();
    }

    /**
     * 获取集合中第一个元素
     *
     * @param collection 集合
     */
    public static <T> Optional<T> last(List<T> collection) {
        if (isNotEmpty(collection)) {
            return Optional.ofNullable(collection.get(size(collection) - 1));
        }
        return Optional.empty();
    }


    /**
     * 获取集合中第一个元素
     *
     * @param collection 集合
     */
    public static <T> Optional<T> onlyOne(Collection<T> collection) {
        if (sizeEquals(collection, 1)) {
            return collection.stream().findFirst();
        }
        return Optional.empty();
    }

    /**
     * 获取集合中第一个元素
     *
     * @param collection 集合
     */
    public static <T> T mostOne(Collection<T> collection, String msg) {
        if (size(collection) > 1) {
            throw new RuntimeException(msg);
        }
        return first(collection).orElse(null);
    }

    /**
     * 获取多个List之间的交集
     *
     * @param elementLists List集合
     */
    public static <E> List<E> retain(List<List<E>> elementLists) {
        Optional<List<E>> result = elementLists.parallelStream().filter(CollectionUtils::isNotEmpty).reduce((a, b) -> {
            a.retainAll(b);
            return a;
        });
        return result.orElse(new ArrayList<>());
    }


    /**
     * 获取多个List之间的交集
     *
     * @param elementLists List集合
     */
    public static <E> Integer findIndex(List<E> elementLists, E e) {
        Predicate<E> predicate = (item) -> item.equals(e);
        return findIndex(elementLists, predicate);
    }

    public static <E, V> Integer findIndex(List<E> elementLists, Function<E, V> function, V v) {
        Predicate<E> predicate = (item) -> function.apply(item).equals(v);
        return findIndex(elementLists, predicate);
    }

    public static <T> List<T> randomSub(List<T> originalList, int subsetSize) {
        List<T> subset = new ArrayList<>();
        List<T> copy = new ArrayList<>(originalList);
        Random random = new Random();
        int originalSize = originalList.size();
        for (int i = 0; i < Math.min(subsetSize, originalSize); i++) {
            int randomIndex = random.nextInt(copy.size());
            subset.add(copy.remove(randomIndex));
        }
        return subset;
    }


    /**
     * 获取多个List之间的交集
     *
     * @param elementLists List集合
     */
    public static <E> Integer findIndex(List<E> elementLists, Predicate<E> predicate) {
        for (int i = 0; i < elementLists.size(); i++) {
            if (predicate.test(elementLists.get(i))) {
                return i;
            }
        }
        return -1;
    }

    /////////////////////////////////////

    /**
     * 计算数字集合的总和
     *
     * @param collection 数字集合
     */
    public static Integer sumInteger(Collection<Integer> collection) {
        return sum(collection, 0, Integer::sum);
    }

    /**
     * @param list            元素集合
     * @param integerFunction 元素提取函数
     */
    public static <T> Integer sumInteger(List<T> list, Function<T, Integer> integerFunction) {
        return sumInteger(list, integerFunction, 0);
    }


    /**
     * @param list            元素集合
     * @param integerFunction 元素提取函数
     */
    public static <T> Integer sumInteger(List<T> list, Function<T, Integer> integerFunction, Integer defaultR) {
        return sum(list, integerFunction, defaultR, Integer::sum);
    }

    /////////////////////////////////////

    /**
     * 计算数字集合的总和
     *
     * @param collection 数字集合
     */
    public static Long sumLong(Collection<Long> collection) {
        return sum(collection, 0L, Long::sum);
    }

    /**
     * @param list            元素集合
     * @param integerFunction 元素提取函数
     */
    public static <T> Long sumLong(List<T> list, Function<T, Long> integerFunction) {
        return sumLong(list, integerFunction, 0L);
    }


    /**
     * @param list            元素集合
     * @param integerFunction 元素提取函数
     */
    public static <T> Long sumLong(List<T> list, Function<T, Long> integerFunction, Long defaultR) {
        return sum(list, integerFunction, defaultR, Long::sum);
    }

    /////////////////////////////////////


    /////////////////////////////////////


    /**
     * 对象集合数字求和
     * 一个对象两个数字属性，分别对两个属性遍历一次就和
     *
     * @param list      对象数字集合
     * @param functions 转数字函数集合
     */
    @SafeVarargs
    public static <T> List<Integer> sumInteger(List<T> list, Function<T, Integer>... functions) {
        Map<Integer, List<Integer>> map = Maps.newLinkedHashMap();
        for (T t : list) {
            for (int i = 0; i < functions.length; i++) {
                List<Integer> integers = map.get(i);
                if (integers == null) {
                    List<Integer> newList = Lists.newArrayListWithExpectedSize(CollectionUtils.size(list));
                    newList.add(functions[i].apply(t));
                    map.put(i, newList);
                } else {
                    integers.add(functions[i].apply(t));
                }
            }
        }
        List<Integer> result = Lists.newArrayList();
        for (Integer key : map.keySet()) {
            result.add(sumInteger(map.get(key)));
        }
        return result;
    }

    @SafeVarargs
    public static <T> List<Long> sumLong(List<T> list, Function<T, Long>... functions) {
        Map<Integer, List<Long>> map = Maps.newLinkedHashMap();
        for (T t : list) {
            for (int i = 0; i < functions.length; i++) {
                List<Long> integers = map.get(i);
                if (integers == null) {
                    List<Long> newList = Lists.newArrayListWithExpectedSize(CollectionUtils.size(list));
                    newList.add(functions[i].apply(t));
                    map.put(i, newList);
                } else {
                    integers.add(functions[i].apply(t));
                }
            }
        }
        List<Long> result = Lists.newArrayList();
        for (Integer key : map.keySet()) {
            result.add(sumLong(map.get(key)));
        }
        return result;
    }


    /**
     * 获取集合第一个元素并返回默认值
     *
     * @param collection 集合
     */
    public static <T, S extends T> T firstDefault(Collection<T> collection, S s) {
        if (isEmpty(collection)) {
            return s;
        }
        return collection.stream().findFirst().orElse(s);
    }


    /**
     * 获取集合第一个元素并返回默认值
     *
     * @param collection 集合
     */
    public static <T, S extends T> T firstDefaultNull(Collection<T> collection) {
        if (isEmpty(collection)) {
            return null;
        }
        return collection.stream().findFirst().orElse(null);
    }

    /**
     * 删除元素
     *
     * @param collection 集合
     * @param predicate  条件
     */
    public static <T> void remove(List<T> collection, Predicate<T> predicate) {
        collection.removeIf(predicate);
    }


    /**
     * 删除元素
     *
     * @param collection 集合
     * @param ts         要删除的元素
     */
    public static <T> void remove(List<T> collection, T[] ts) {
        if (isNotEmpty(ts)) {
            for (T t : ts) {
                collection.remove(t);
            }
        }
    }

    /**
     * 过滤接口,如果true则过滤
     *
     * @param <T>
     */
    public interface Filter<T> {
        boolean filter(T t);
    }

    /**
     * 删除集合元素(JDK1.7)
     *
     * @param list   集合
     * @param filter 条件
     */
    public static <T> void remove(List<T> list, Filter<T> filter) {
        list.removeIf(filter::filter);
    }

    /**
     * 判断数组是否为空
     *
     * @param array 数组
     */
    public static <T> boolean isEmpty(T[] array) {
        return Objects.isNull(array) || array.length == ZERO;
    }

    /**
     * 判断数组是否不为空
     *
     * @param array 数组
     */
    public static <T> boolean isNotEmpty(T[] array) {
        return !isEmpty(array);
    }

    /**
     * 计算集合的总和
     *
     * @param collection  集合
     * @param defaultT    默认值
     * @param accumulator 累加器
     */
    public static <T> T sum(Collection<T> collection, T defaultT, BinaryOperator<T> accumulator) {
        if (isEmpty(collection)) {
            return defaultT;
        }
        return collection.stream().filter(Objects::nonNull).reduce(defaultT, accumulator);
    }

    /**
     * @param list            元素集合
     * @param integerFunction 元素提取函数
     * @param defaultR        默认值
     * @param accumulator     累加器
     */
    public static <T, R> R sum(List<T> list, Function<T, R> integerFunction, R defaultR, BinaryOperator<R> accumulator) {
        if (CollectionUtils.isEmpty(list)) {
            return defaultR;
        }
        return list.stream().map(integerFunction).filter(Objects::nonNull).reduce(defaultR, accumulator);
    }


    /**
     * 将字符串集合转为字符串数组
     *
     * @param collection 集合
     */
    public static <T> T[] toArray(Collection<T> collection, Class classes) {
        if (Objects.isNull(collection)) {
            collection = Lists.newArrayList();
        }
        return collection.toArray((T[]) Array.newInstance(classes, collection.size()));
    }

    /**
     * 将字符串集合转为字符串数组
     *
     * @param collection 集合
     */
    public static <T> T[] toArray(Collection<T> collection, T[] t) {
        return collection.toArray(t);
    }

    /**
     * 将数组转为集合
     *
     * @param array 数组
     */
    public static <T> List<T> toList(T[] array) {
        if (Objects.isNull(array)) {
            return Lists.newArrayList();
        }
        return Arrays.stream(array).collect(Collectors.toList());
    }


    /**
     * 将数组转为集合
     *
     * @param collection 集合
     */
    public static <T> List<T> toList(Collection<T> collection) {
        return new ArrayList<>(collection);
    }


    /**
     * 获取集合交集
     *
     * @param collection1 集合1
     * @param collection2 集合2
     */
    public static <T> List<T> intersection(List<? extends T> collection1, List<? extends T> collection2) {
        if (isEmpty(collection1) || isEmpty(collection2)) {
            return Lists.newArrayList();
        }
        List<T> result = Lists.newArrayList();
        List<? extends T> smaller = collection1;
        List<? extends T> larger = collection2;
        if (collection1.size() > collection2.size()) {
            smaller = collection2;
            larger = collection1;
        }
        HashSet<T> hashSet = new HashSet<>(smaller);
        for (T e : larger) {
            if (hashSet.contains(e)) {
                result.add(e);
                hashSet.remove(e);
            }
        }
        return result;
    }

    /**
     * 包含
     *
     * @param collection 集合
     * @param t          对象
     */
    public static <T> boolean contains(Collection<T> collection, T t) {
        return isNotEmpty(collection) && collection.contains(t);
    }

    /**
     * 包含
     *
     * @param collection 集合
     * @param t          对象
     */
    public static <T, R> boolean contains(Collection<R> collection, Function<R, T> function, T t) {
        if (CollectionUtils.isEmpty(collection)) {
            return false;
        }
        for (R r : collection) {
            T apply = function.apply(r);
            if (apply != null) {
                if (apply.equals(t)) {
                    return true;
                }
            }
        }
        return false;
    }


    /**
     * 不包含
     *
     * @param collection 集合
     * @param t          对象
     */
    public static <T> boolean nonContains(Collection<T> collection, T t) {
        return !contains(collection, t);
    }


    /**
     * 判断集合是否有交集
     *
     * @param collection1 集合1
     * @param collection2 集合2
     *                    ListUtils#intersection(List, List)
     */
    public static <T> boolean hasIntersection(List<? extends T> collection1, List<? extends T> collection2) {
        if (isEmpty(collection1) || isEmpty(collection2)) {
            return false;
        }
        List<? extends T> smaller = collection1;
        List<? extends T> larger = collection2;
        if (collection1.size() > collection2.size()) {
            smaller = collection2;
            larger = collection1;
        }
        for (T e : larger) {
            if (smaller.contains(e)) {
                return true;
            }
        }
        return false;
    }

    /**
     * 判断集合是否只有一个元素
     *
     * @param collection 集合
     */
    public static <T> boolean isOne(Collection<T> collection) {
        return size(collection) == 1;
    }


    /**
     * 判断集合第一个元素
     *
     * @param collection 集合
     */
    public static <T> Optional<T> one(Collection<T> collection) {
        if (isOne(collection)) {
            return collection.stream().findFirst();
        }
        return Optional.empty();
    }


    /**
     * 判断集合是否只有一个元素
     *
     * @param collection 集合
     * @param checkItem  是否检测元素
     */
    public static <T> boolean isOne(Collection<T> collection, boolean checkItem) {
        boolean isOne = size(collection) == 1;
        if (isOne && checkItem) {
            final List<T> collect = new ArrayList<>(collection);
            final T t = collect.get(ZERO);
            return Objects.nonNull(t);
        }
        return isOne;
    }


    /**
     * 判断集合是否不只有一个元素
     *
     * @param collection 集合
     */
    public static <T> boolean nonOne(Collection<T> collection) {
        return !isOne(collection);
    }


    public static <T> List<T> subList(List<T> list, int start, int end) {
        start = Math.max(0, start);
        end = Math.min(end, list.size());
        return list.subList(start, end);
    }

    /**
     * 字符串长度切分
     *
     * @param list 集合
     * @param lens 长度集合
     */
    public static <T> List<List<T>> lengthSplit(List<T> list, int... lens) {
        List<List<T>> result = Lists.newArrayList();
        int index = 0;
        for (int len : lens) {
            if (index > list.size()) {
                result.add(list);
                return result;
            } else {
                int end = Math.min(len + index, list.size());
                result.add(list.subList(index, end));
                index += len;
            }
        }
        return result;
    }

    /**
     * 降序排序
     *
     * @param list  数据集合
     * @param funTv 获取比较参数
     */
    public static <T, V extends Comparable<V>> void desc(List<T> list, Function<T, V> funTv) {
        if (isNotEmpty(list)) {
            list.sort((item1, item2) -> funTv.apply(item2).compareTo(funTv.apply(item1)));
        }
    }

    /**
     * 升序排序
     *
     * @param list  数据集合
     * @param funTv 获取比较参数
     */
    public static <T, V extends Comparable<V>> void asc(List<T> list, Function<T, V> funTv) {
        if (isNotEmpty(list)) {
            list.sort(Comparator.comparing(funTv));
        }
    }


    public static <T> void batch(List<T> source, Consumer<List<T>> consumer, Integer batchSize) {
        log.info("Consumer正在批量处理数据:source.size={},batchSize={}", CollectionUtils.size(source), batchSize);
        Integer size = source.size();
        int times = size / batchSize;
        for (int i = 0; i < times; i++) {
            dealWithData(i, source.subList(i * batchSize, (i + 1) * batchSize), consumer);
        }
        if (size % batchSize > 0) {
            dealWithData(times, source.subList(times * batchSize, size), consumer);
        }
    }

    /**
     * 获取第times的List集合
     *
     * @param source    源数据
     * @param times     第几次
     * @param batchSize 每次多少
     */
    public static <T> List<T> getTimesList(List<T> source, Integer times, Integer batchSize) {
        if (CollectionUtils.isEmpty(source)) {
            return new ArrayList<>(0);
        }
        int toIndex = Math.min(times * batchSize + batchSize, CollectionUtils.size(source));
        int fromIndex = Math.min(times * batchSize, CollectionUtils.size(source));
        return source.subList(fromIndex, toIndex);
    }

    private static <T> void dealWithData(int times, List<T> partList, Consumer<List<T>> consumer) {
        log.info("Consumer正在部分处理数据:partList.size={},times={}", CollectionUtils.size(partList), times);
        if (CollectionUtils.isNotEmpty(partList) && Objects.nonNull(consumer)) {
            try {
                consumer.accept(partList);
            } catch (Exception e) {
                log.error("dealWithData.times={},e={}", times, e);
            }
        }
    }


    public static <T, R> List<Optional<R>> batch(List<T> source, Function<List<T>, R> function, Integer batchSize) {
        log.info("Function正在批量处理数据:source.size={},batchSize={}", CollectionUtils.size(source), batchSize);
        Integer size = source.size();
        int times = size / batchSize;
        List<Optional<R>> result = Lists.newArrayListWithCapacity(batchSize);
        for (int i = 0; i < times; i++) {
            Optional<R> r = dealWithData(i, source.subList(i * batchSize, (i + 1) * batchSize), function);
            result.add(r);
        }
        if (size % batchSize > 0) {
            Optional<R> r = dealWithData(times, source.subList(times * batchSize, size), function);
            result.add(r);
        }
        return result;
    }

    private static <T, R> Optional<R> dealWithData(int times, List<T> partList, Function<List<T>, R> function) {
        log.info("Function正在部分处理数据:partList.size={},times={}", CollectionUtils.size(partList), times);
        if (CollectionUtils.isNotEmpty(partList) && Objects.nonNull(function)) {
            try {
                R apply = function.apply(partList);
                return Optional.ofNullable(apply);
            } catch (Exception e) {
                log.error("dealWithData.times={},e={}", times, e);
            }
            return Optional.empty();
        }
        return Optional.empty();
    }


    public <A1, A2, A3> List<A3> to(A1[] split1, A2[] split2, BiFunction<A1, A2, A3> function) {
        boolean sizeEquals = sizeEquals(split1, split2);
        Assert.check(sizeEquals, "数据不合法!");
        List<A3> tos = Lists.newArrayListWithCapacity(size(split1));
        for (int i = 0; i < split1.length; i++) {
            A1 name = split1[i];
            A2 value = split2[i];
            A3 apply = function.apply(name, value);
            tos.add(apply);
        }
        return tos;
    }

    public static <T> T randomOne(List<T> list, Predicate<T> predicate) {
        return randomOne(list, predicate, null);
    }

    public static <T> T randomOne(List<T> list, Predicate<T> predicate, T dfValue) {
        Random random = new Random();
        List<T> tempList = new ArrayList<>(list);
        while (!tempList.isEmpty()) {
            int size = tempList.size();
            int index = random.nextInt(size);
            T t = tempList.get(index);
            if (predicate.test(t)) {
                return t;
            } else {
                tempList.remove(index);
            }
        }
        return dfValue;
    }


    public static <T> List<T> random(List<T> list, int count) {
        return random(list, count, size(list));
    }

    public static <T> List<T> random(List<T> list, int count, int maxRandomTimes) {
        if (isEmpty(list) || count <= 0) {
            return Collections.emptyList();
        }
        int size = list.size();
        if (count >= size) {
            return list;
        }
        Assert.check(maxRandomTimes >= count, "参数设置错误!");
        List<T> randomElements = new ArrayList<>();
        Random random = new Random();
        int randomTimes = 0;
        while (randomElements.size() < count && randomTimes < maxRandomTimes) {
            int index = random.nextInt(size);
            T element = list.get(index);
            if (!randomElements.contains(element)) {
                randomElements.add(element);
            }
            randomTimes++;
        }
        return randomElements;
    }


    @Setter
    @Getter
    @ToString
    public static class BatchItem {
        private long startIndex;
        private long batchSize;
        private long endIndex;
        private int currentBatch;
    }

    @Setter
    @Getter
    @ToString
    public static class BatchIndex {
        private long min;
        private long max;
    }


    public static List<BatchItem> batch(long startIndex, long endIndex, int batchSize) {
        List<BatchItem> batchItemList = Lists.newArrayList();
        if (startIndex > endIndex) {
            return batchItemList;
        }
        if (batchSize < 1) {
            return batchItemList;
        }
        int currentBatch = 0;
        for (long i = startIndex; i < endIndex; i = i + batchSize) {
            BatchItem batchItem = new BatchItem();
            batchItem.setBatchSize(batchSize);
            batchItem.setStartIndex(i);
            batchItem.setEndIndex(Math.min(i + batchSize - 1, endIndex));
            batchItem.setCurrentBatch(++currentBatch);
            batchItemList.add(batchItem);
        }
        return batchItemList;
    }

    @Getter
    @Setter
    @ToString
    public static abstract class TreeNode implements Serializable {
        private Integer id;
        private Integer parentId;
        private String name;
        private List<TreeNode> children;

        public TreeNode(Integer id, Integer parentId, String name) {
            this.id = id;
            this.parentId = parentId;
            this.name = name;
            this.children = new ArrayList<>();
        }

        public void addChild(TreeNode child) {
            children.add(child);
        }
    }

    public static <T extends TreeNode> List<T> buildTree(List<T> nodes) {
        Map<Integer, T> nodeMap = new HashMap<>();
        for (T node : nodes) {
            if (Objects.isNull(node.getParentId())) {
                node.setParentId(0);
            }
            nodeMap.put(node.getId(), node);
        }
        List<T> tree = new ArrayList<>();
        for (T node : nodes) {
            if (node.getParentId() == 0) {
                tree.add(attachChildren(node, nodeMap));
            }
        }
        return tree;
    }

    private static <T extends TreeNode> T attachChildren(T parent, Map<Integer, T> nodeMap) {
        for (T child : nodeMap.values()) {
            if (Objects.equals(child.getParentId(), parent.getId())) {
                T childNode = attachChildren(child, nodeMap);
                parent.addChild(childNode);
            }
        }
        return parent;
    }

    public static <T> void randomAdd(List<T> list, T t) {
        if (t == null || list == null) {
            return;
        }
        int random = random(CollectionUtils.size(list));
        list.add(random, t);
    }

    private static int random(int bound) {
        if (bound == 0) {
            return 0;
        }
        Random random = new Random();
        return random.nextInt(bound) + 1;
    }

    public static <T> List<T> randomN(List<T> list, Predicate<T> predicate, int n) {
        return randomN(list, predicate, n, null, null);
    }

    public static <P, T> List<T> randomN(List<T> list, Predicate<T> predicate, int n, P p, BiConsumer<P, T> testBeforeConsumer) {
        if (CollectionUtils.isEmpty(list)) {
            return new ArrayList<>();
        }
        int size = CollectionUtils.size(list);
        if (size <= n) {
            if (Objects.nonNull(testBeforeConsumer)) {
                for (T t : list) {
                    testBeforeConsumer.accept(p, t);
                }
            }
            return list.stream().filter(predicate).collect(Collectors.toList());
        }
        Random random = new Random();
        List<T> result = new ArrayList<>();
        List<T> copyList = new ArrayList<>(list);
        while (result.size() < n && !copyList.isEmpty()) {
            int index = random.nextInt(copyList.size());
            T element = copyList.get(index);
            if (Objects.nonNull(testBeforeConsumer)) {
                testBeforeConsumer.accept(p, element);
            }
            if (predicate.test(element) && !result.contains(element)) {
                result.add(element);
                copyList.remove(index);
            } else {
                copyList.remove(index);
            }
        }
        return result;
    }

    /**
     * 按照权重平分钱(规则：前N-1个元素按照权重获取平分数值，第N个元素平分数值为:前N-1之和的余数，主要是因为除法有精度问题，元素相加之后可能无法和Total总数相等)
     *
     * @param total                  总共被平分的钱数
     * @param ts                     参与分钱的元素
     * @param totalWeightFunction    计算参与总钱数的函数
     * @param totalPartitionFunction 计算平分总钱数的函数
     * @param consumer               每个元素获得平分钱数的函数
     */
    public static <T> void partitionBigDecimal(BigDecimal total, List<T> ts, Function<T, BigDecimal> totalWeightFunction, Function<T, BigDecimal> totalPartitionFunction, BiConsumer<T, BigDecimal> consumer) {
        if (CollectionUtils.isEmpty(ts) || BigDecimalUtils.nullToZero(total).compareTo(BigDecimal.ZERO) <= 0) {
            return;
        }
        log.info("shareBigDecimal.total={}", total);
        BigDecimal totalWeight = CollectionUtils.sum(ts, totalWeightFunction, BigDecimal.ZERO, BigDecimal::add);
        for (int i = 0; i < ts.size(); i++) {
            T t = ts.get(i);
            if (i == ts.size() - 1) {
                BigDecimal bigDecimal = CollectionUtils.sum(ts, totalPartitionFunction, BigDecimal.ZERO, BigDecimal::add);
                BigDecimal subtract = total.subtract(bigDecimal);
                consumer.accept(t, subtract);
            } else {
                BigDecimal eachWeight = totalWeightFunction.apply(t);
                BigDecimal eachWeightRate = BigDecimalUtils.divideDown(eachWeight, totalWeight, 5);
                BigDecimal eachWeightBigDecimal = eachWeightRate.multiply(total);
                consumer.accept(t, eachWeightBigDecimal);
            }
        }
    }


    public static <T> List<T> page(List<T> ts, int currentPage, int pageSize) {
        if (CollectionUtils.isEmpty(ts) || currentPage < 1 || pageSize < 1) {
            return Lists.newArrayListWithCapacity(0);
        }
        int skip = (currentPage - 1) * pageSize;
        return ts.stream().skip(skip).limit(pageSize).collect(Collectors.toList());
    }

}
